#include <jni.h>
#include "utils.h"
#include <math.h>

JNIEXPORT jobject JNICALL
Java_com_yochi_pictureseditor_effects_effectsimpl_EffectSpectrumCorrection_process(JNIEnv* env, jobject this, jobject imageObject) {


	/* ------ Parse entries ------ */

	// get entry image
	jclass imageimplClass = 		(*env)->GetObjectClass(env, imageObject);


	/* ------ Parse entries ------ */

	// image constructor methods
	jmethodID midConstructor = 		(*env)->GetMethodID(env, imageimplClass, "<init>", 			"(III)V");

	// image getter methods
	jmethodID midGetHauteur = 		(*env)->GetMethodID(env, imageimplClass, "getHauteur", 		"()I");
	jmethodID midGetLargeur = 		(*env)->GetMethodID(env, imageimplClass, "getLargeur", 		"()I");
    jmethodID midGetProfondeur = 	(*env)->GetMethodID(env, imageimplClass, "getProfondeur", 	"()I");
    jmethodID midGetPixel = 		(*env)->GetMethodID(env, imageimplClass, "getPixel", 		"(III)C");
    jmethodID midGetAveragePixel = 	(*env)->GetMethodID(env, imageimplClass, "getAveragePixel", "(II)C");

    // image setter methods
    jmethodID midSetPixel = 		(*env)->GetMethodID(env, imageimplClass, "setPixel", 		"(IIIC)V");


    /* ------ Recover attributes ------ */

    // get image parameters
    int hauteur = 					(*env)->CallIntMethod(env, imageObject, midGetHauteur);
    int largeur = 					(*env)->CallIntMethod(env, imageObject, midGetLargeur);
    int profondeur = 				(*env)->CallIntMethod(env, imageObject, midGetProfondeur);


    /* ------ Instantiate result image ------ */

    jobject imageResult = 			imageObject;

    /* ------ Process effect ------ */

    int p, l, h;
    float pixelValue;
    char newPixelValue;
    char lowPixel = 128;
    char highPixel = 128;

    // get lowPixel and highPixel values for image
	for(l=0; l<largeur; l++) {
		for(h=0; h<hauteur; h++) {

			if(profondeur == 4) {
				newPixelValue = 	((*env)->CallIntMethod(env, imageObject, midGetPixel, 0, l, h)
								+	 (*env)->CallIntMethod(env, imageObject, midGetPixel, 1, l, h)
								+	 (*env)->CallIntMethod(env, imageObject, midGetPixel, 2, l, h)) / 3;
			} else {
				newPixelValue = 	 (*env)->CallIntMethod(env, imageObject, midGetPixel, 0, l, h);
			}

			if(  newPixelValue < lowPixel ) {
				lowPixel = newPixelValue;
			} else if ( newPixelValue > highPixel ) {
				highPixel = newPixelValue;
			}
		}
	}

    // adjust spectrum if needed
   // if(lowPixel > 0 && highPixel < 255) {
        for(p=0; p<profondeur; p++) {
        	for(l=0; l<largeur; l++) {
        		for(h=0; h<hauteur; h++) {

        			if( (profondeur == 4 && p < 3)  ||  (profondeur == 2 && p < 1) ) {

        				// get pixel value and cast to float for computation
        				pixelValue = (*env)->CallIntMethod(env, imageObject, midGetPixel, p, l, h);
        				// correct pixel value
        				newPixelValue = (char) lroundf((pixelValue - (float)lowPixel) * (255.0f / ((float)highPixel-(float)lowPixel)));

        				(*env)->CallVoidMethod(env, imageResult, midSetPixel, p, l, h, newPixelValue);
        			}
        		}
        	}
        }
    //}

    return imageResult;
}

